home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / CNews / Source / libc / datetok.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-01-14  |  8.9 KB  |  290 lines

  1. /*
  2.  * datetok - date tokenisation
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <string.h>
  8. #include <sys/types.h>        /* for dateconv.h */
  9. #include "dateconv.h"
  10. #include "datetok.h"
  11.  
  12. /* imports */
  13. int dtok_numparsed;
  14.  
  15. /*
  16.  * to keep this table reasonably small, we compact the lexval for TZ and DTZ
  17.  * entries and truncate the text field at MAXTOKLEN characters.
  18.  * the text field is not guaranteed to be NUL-terminated.
  19.  * ST = Standard Time; DT = Daylight Time.
  20.  */
  21. static datetkn datetktbl[] = {
  22. /*    text        token    lexval */
  23.     "acsst",    DTZ,    PACK(630),    /* Cent. Australia */
  24.     "acst",        TZ,    PACK(570),    /* Cent. Australia */
  25.     "adt",        DTZ,    PACK(-180),    /* Atlantic DT */
  26.     "aesst",    DTZ,    PACK(660),    /* E. Australia */
  27.     "aest",        TZ,    PACK(600),    /* Australia Eastern ST */
  28.     "akdt",        DTZ,    PACK(-480),    /* Alaska DT */
  29.     "akst",        TZ,    PACK(-540),    /* Alaska ST */
  30.     "am",        AMPM,    AM,
  31.     "apr",        MONTH,    4,
  32.     "april",    MONTH,    4,
  33.     "ast",        TZ,    PACK(-240),    /* Atlantic ST (Canada) */
  34.     "at",        IGNORE,    0,        /* "at" (throwaway) */
  35.     "aug",        MONTH,    8,
  36.     "august",    MONTH,    8,
  37.     "awst",        TZ,    PACK(480),    /* W. Australia */
  38.     "bst",        DTZ,    PACK(60),    /* British Summer Time */
  39.     "cadt",        DTZ,    PACK(630),    /* Central Australian DT */
  40.     "cast",        TZ,    PACK(570),    /* Central Australian ST */
  41.     "cat",        TZ,    PACK(-600),    /* Central Alaska Time */
  42.     "cct",        TZ,    PACK(480),    /* China Coast */
  43.     "cdt",        DTZ,    PACK(-300),    /* Central DT */
  44.     "cest",        DTZ,    PACK(120),    /* Central Europe Summer Time */
  45.     "cet",        TZ,    PACK(60),    /* Central European Time */
  46.     "cetdst",    DTZ,    PACK(120),    /* Central European DT */
  47.     "cst",        TZ,    PACK(-360),    /* Central ST */
  48.     "dec",        MONTH,    12,
  49.     "decemb",    MONTH,    12,
  50.     "dnt",        TZ,    PACK(60),    /* Dansk Normal Tid */
  51. /*XX*/    "dst",        IGNORE,    0,
  52.     "eadt",        DTZ,    PACK(660),    /* East Australian DT */
  53.     "east",        TZ,    PACK(600),    /* East Australian ST */
  54.     "edt",        DTZ,    PACK(-240),    /* Eastern DT */
  55.     "eest",        DTZ,    PACK(180),    /* Eastern Europe Summer */
  56.     "eet",        TZ,    PACK(120),    /* Eastern Europe */
  57.     "eetdst",    DTZ,    PACK(180),    /* Eastern Europe */
  58.     "est",        TZ,    PACK(-300),    /* Eastern ST */
  59.     "feb",        MONTH,    2,
  60.     "februa",    MONTH,    2,
  61.     "fri",        IGNORE,    5,
  62.     "friday",    IGNORE,    5,
  63.     "fst",        DTZ,    PACK(120),    /* French Summer Time */
  64.     "fwt",        TZ,    PACK(60),    /* French Winter Time  */
  65.     "gmt",        TZ,    PACK(0),    /* Greenwich Mean Time */
  66.     "gst",        TZ,    PACK(600),    /* Guam ST */
  67.     "hadt",        DTZ,    PACK(-540),    /* Hawaii-Aleutian DT */
  68.     "hast",        TZ,    PACK(-600),    /* Hawaii-Aleutian ST */
  69.     "hkt",        TZ,    PACK(480),    /* Hong Kong Time */
  70.     "hst",        TZ,    PACK(-600),    /* Hawaii ST */
  71.     "idle",        TZ,    PACK(720),    /* Intl. Date Line, East */
  72.     "idlw",        TZ,    PACK(-720),    /* Intl. Date Line, West */
  73.     "idt",        DTZ,    PACK(180),    /* Israel DT */
  74.     "ist",        TZ,    PACK(120),    /* Israel */
  75.     "jan",        MONTH,    1,
  76.     "januar",    MONTH,    1,
  77.     "jst",        TZ,    PACK(540),    /* Japan ST */
  78.     "jul",        MONTH,    7,
  79.     "july",        MONTH,    7,
  80.     "jun",        MONTH,    6,
  81.     "june",        MONTH,    6,
  82.     "kdt",        DTZ,    PACK(600),    /* Korea DT */
  83.     "kst",        TZ,    PACK(540),    /* Korea ST */
  84. /*XX*/    "ligt",        TZ,    PACK(600),    /* From Melbourne, Australia */
  85.     "mar",        MONTH,    3,
  86.     "march",    MONTH,    3,
  87.     "may",        MONTH,    5,
  88.     "mdt",        DTZ,    PACK(-360),    /* Mountain DT */
  89.     "mest",        DTZ,    PACK(120),    /* Middle Europe Summer Time */
  90.     "mesz",        DTZ,    PACK(120),    /* Mittel-Europaeische Sommerzeit */
  91.     "met",        TZ,    PACK(60),    /* Middle Europe Time */
  92.     "metdst",    DTZ,    PACK(120),    /* Middle Europe DT */
  93.     "mewt",        TZ,    PACK(60),    /* Middle Europe Winter Time */
  94.     "mez",        TZ,    PACK(60),    /* Mittel-Europaeische Zeit */
  95.     "mon",        IGNORE,    1,
  96.     "monday",    IGNORE,    1,
  97.     "mst",        TZ,    PACK(-420),    /* Mountain ST */
  98.     "ndt",        DTZ,    PACK(-150),    /* Nfld. DT */
  99. /*XXN*/    "nft",        TZ,    PACK(-210),    /* Newfoundland ST */
  100. /*XX*/    "nor",        TZ,    PACK(60),    /* Norway ST */
  101.     "nov",        MONTH,    11,
  102.     "novemb",    MONTH,    11,
  103.     "nst",        TZ,    PACK(-210),    /* Nfld. ST */
  104.     "nzdt",        DTZ,    PACK(780),    /* New Zealand DT */
  105.     "nzst",        TZ,    PACK(720),    /* New Zealand ST */
  106.     "nzt",        TZ,    PACK(720),    /* New Zealand Time */
  107.     "oct",        MONTH,    10,
  108.     "octobe",    MONTH,    10,
  109.     "on",        IGNORE,    0,        /* "on" (throwaway) */
  110.     "pdt",        DTZ,    PACK(-420),    /* Pacific DT */
  111.     "pm",        AMPM,    PM,
  112.     "pst",        TZ,    PACK(-480),    /* Pacific ST */
  113.     "sadt",        DTZ,    PACK(630),    /* S. Australian DT */
  114.     "sast",        TZ,    PACK(570),    /* South Australian ST */
  115.     "sat",        IGNORE,    6,
  116.     "saturd",    IGNORE,    6,
  117.     "sep",        MONTH,    9,
  118.     "sept",        MONTH,    9,
  119.     "septem",    MONTH,    9,
  120.     "sst",        DTZ,    PACK(120),    /* Swedish Summer Time */
  121.     "sun",        IGNORE,    0,
  122.     "sunday",    IGNORE,    0,
  123.     "swt",        TZ,    PACK(60),    /* Swedish Winter Time  */
  124.     "thu",        IGNORE,    4,
  125.     "thur",        IGNORE,    4,
  126.     "thurs",    IGNORE,    4,
  127.     "thursd",    IGNORE,    4,
  128.     "tue",        IGNORE,    2,
  129.     "tues",        IGNORE,    2,
  130.     "tuesda",    IGNORE,    2,
  131.     "ut",        TZ,    PACK(0),
  132.     "utc",        TZ,    PACK(0),
  133.     "wast",        TZ,    PACK(480),    /* West Australian ST */
  134.     "wat",        TZ,    PACK(-60),    /* West Africa Time */
  135.     "wed",        IGNORE,    3,
  136.     "wednes",    IGNORE,    3,
  137.     "weds",        IGNORE,    3,
  138.     "west",        DTZ,    PACK(60),    /* Western Europe Summer */
  139.     "wet",        TZ,    PACK(0),    /* Western Europe */
  140.     "wetdst",    DTZ,    PACK(60),    /* Western Europe */
  141.     "wst",        TZ,    PACK(480),    /* West Australian ST */
  142.     "ydt",        DTZ,    PACK(-480),    /* Yukon DT */
  143.     "yst",        TZ,    PACK(-540),    /* Yukon ST */
  144.     "zp4",        TZ,    PACK(-240),    /* GMT +4  hours. */
  145.     "zp5",        TZ,    PACK(-300),    /* GMT +5  hours. */
  146.     "zp6",        TZ,    PACK(-360),    /* GMT +6  hours. */
  147. };
  148.  
  149. #if    0
  150. /*
  151.  * these time zones are orphans, i.e. the name is also used by a more
  152.  * likely-to-appear time zone
  153.  */
  154.     "adt",        DTZ,    PACK(0),    /* Azores DT */
  155.     "adt",        DTZ,    PACK(-240),    /* Acre DT */
  156.     "ast",        TZ,    PACK(-60),    /* Azores ST */
  157.     "ast",        TZ,    PACK(-300),    /* Acre ST */
  158.     "bst",        TZ,    PACK(-180),    /* Brazil ST */
  159.     "cdt",        DTZ,    PACK(-180),    /* Chile DT */
  160.     "cdt",        DTZ,    PACK(-240),    /* Cuba DT */
  161.     "cdt",        DTZ,    PACK(540),    /* China DT */
  162.     "cst",        TZ,    PACK(-240),    /* Chile ST */
  163.     "cst",        TZ,    PACK(-300),    /* Cuba ST */
  164.     "cst",        TZ,    PACK(480),    /* China ST */
  165.     "edt",        DTZ,    PACK(-300),    /* Easter Island DT */
  166.     "edt",        DTZ,    PACK(-120),    /* East Brazil DT */
  167.     "edt",        DTZ,    PACK(660),    /* Australian Eastern DT */
  168.     "est",        TZ,    PACK(-360),    /* Easter Island ST */
  169.     "est",        TZ,    PACK(-180),    /* East Brazil ST */
  170.     "est",        TZ,    PACK(600),    /* Australian Eastern ST */
  171.     "fdt",        DTZ,    PACK(-60),    /* Fernando de Noronha DT */
  172.     "fst",        TZ,    PACK(-120),    /* Fernando de Noronha ST */
  173.     "ist",        TZ,    PACK(330),    /* Indian ST */
  174.     "sst",        TZ,    PACK(-660),    /* Samoa ST */
  175.     "sst",        TZ,    PACK(480),    /* Singapore ST */
  176.     "wdt",        DTZ,    PACK(-180),    /* Western Brazil DT */
  177.     "wet",        TZ,    PACK(60),    /* Western European Time */
  178.     "wst",        TZ,    PACK(-240),    /* Western Brazil ST */
  179. /* military timezones are deprecated by RFC 1123 section 5.2.14 */
  180.     "a",        TZ,    PACK(60),    /* UTC+1h */
  181.     "b",        TZ,    PACK(120),    /* UTC+2h */
  182.     "c",        TZ,    PACK(180),    /* UTC+3h */
  183.     "d",        TZ,    PACK(240),    /* UTC+4h */
  184.     "e",        TZ,    PACK(300),    /* UTC+5h */
  185.     "f",        TZ,    PACK(360),    /* UTC+6h */
  186.     "g",        TZ,    PACK(420),    /* UTC+7h */
  187.     "h",        TZ,    PACK(480),    /* UTC+8h */
  188.     "i",        TZ,    PACK(540),    /* UTC+9h */
  189.     "k",        TZ,    PACK(600),    /* UTC+10h */
  190.     "l",        TZ,    PACK(660),    /* UTC+11h */
  191.     "m",        TZ,    PACK(720),    /* UTC+12h */
  192.     "n",        TZ,    PACK(-60),    /* UTC-1h */
  193.     "o",        TZ,    PACK(-120),    /* UTC-2h */
  194.     "p",        TZ,    PACK(-180),    /* UTC-3h */
  195.     "q",        TZ,    PACK(-240),    /* UTC-4h */
  196.     "r",        TZ,    PACK(-300),    /* UTC-5h */
  197.     "s",        TZ,    PACK(-360),    /* UTC-6h */
  198.     "t",        TZ,    PACK(-420),    /* UTC-7h */
  199.     "u",        TZ,    PACK(-480),    /* UTC-8h */
  200.     "v",        TZ,    PACK(-540),    /* UTC-9h */
  201.     "w",        TZ,    PACK(-600),    /* UTC-10h */
  202.     "x",        TZ,    PACK(-660),    /* UTC-11h */
  203.     "y",        TZ,    PACK(-720),    /* UTC-12h */
  204.     "z",        TZ,    PACK(0),    /* UTC */
  205. #endif
  206.  
  207. static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
  208.  
  209. datetkn *
  210. datetoktype(s, bigvalp)
  211. char *s;
  212. int *bigvalp;
  213. {
  214.     register char *cp = s;
  215.     register char c = *cp;
  216.     static datetkn t;
  217.     register datetkn *tp = &t;
  218.  
  219.     if (isascii(c) && isdigit(c)) {
  220.         register int len = strlen(cp);
  221.  
  222.         if (len > 3 && (cp[1] == ':' || cp[2] == ':'))
  223.             tp->type = TIME;
  224.         else {
  225.             if (bigvalp != NULL)
  226.                 /* won't fit in tp->value */
  227.                 *bigvalp = atoi(cp);
  228.             if (len == 4)
  229.                 tp->type = YEAR;
  230.             else if (++dtok_numparsed == 1)
  231.                 tp->type = DAY;
  232.             else
  233.                 tp->type = YEAR;
  234.         }
  235.     } else if (c == '-' || c == '+') {
  236.         register int val = atoi(cp + 1);
  237.         register int hr =  val / 100;
  238.         register int min = val % 100;
  239.  
  240.         val = hr*60 + min;
  241.         if (c == '-')
  242.             val = -val;
  243.         tp->type = TZ;
  244.         TOVAL(tp, val);
  245.     } else {
  246.         char lowtoken[TOKMAXLEN+1];
  247.         register char *ltp = lowtoken, *endltp = lowtoken+TOKMAXLEN;
  248.  
  249.         /* copy to lowtoken to avoid modifying s */
  250.         while ((c = *cp++) != '\0' && ltp < endltp)
  251.             *ltp++ = (isascii(c) && isupper(c)? tolower(c): c);
  252.         *ltp = '\0';
  253.         tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
  254.         if (tp == NULL) {
  255.             tp = &t;
  256.             tp->type = IGNORE;
  257.         }
  258.     }
  259.     return tp;
  260. }
  261.  
  262. /*
  263.  * Binary search -- from Knuth (6.2.1) Algorithm B.  Special case like this
  264.  * is WAY faster than the generic bsearch().
  265.  */
  266. datetkn *
  267. datebsearch(key, base, nel)
  268. register char *key;
  269. register datetkn *base;
  270. unsigned int nel;
  271. {
  272.     register datetkn *last = base + nel - 1, *position;
  273.     register int result;
  274.  
  275.     while (last >= base) {
  276.         position = base + ((last - base) >> 1);
  277.         result = key[0] - position->token[0];
  278.         if (result == 0) {
  279.             result = strncmp(key, position->token, TOKMAXLEN);
  280.             if (result == 0)
  281.                 return position;
  282.         }
  283.         if (result < 0)
  284.             last = position - 1;
  285.         else
  286.             base = position + 1;
  287.     }
  288.     return 0;
  289. }
  290.